package sys;

import java.util.*;
import java.sql.*;
import java.io.*;

import sys.transport.*;
import sys.logic.*;
import sys.message.*;
import sys.timer.TimerClient;
import sys.database.*;
import sys.tests.*;
import sys.utils.*;
import org.json.*;

public class Main
{ 
    static private void readParams(String confFilePath)
    {
        File confFile = new File(confFilePath);
        String conf = ReadWriteTextFile.getContents(confFile);

        try
        {
            JSONObject jo = new JSONObject(conf);
            sysa = new StringBuffer(jo.getString("sysaMailAddress"));
            server = new StringBuffer(jo.getString("server"));
            portSMTP = jo.getString("smtpport");
            payingSystem = new StringBuffer(jo.getString("payingSystemMailAddress"));
            userName = new StringBuffer(jo.getString("userName"));

            DBHost = new StringBuffer(jo.getString("DBHost"));
            DBUser = new StringBuffer(jo.getString("DBUser"));
            DBPass = new StringBuffer(jo.getString("DBPass"));

            quantity = jo.getInt("quantity");
        }
        catch(JSONException e)
        {
            System.out.println("Receiver : Error while parsing config file : " + e.getMessage());
        }
    }

    public static void main(String args[])
    {
        if (args.length > 0 && args[0].compareTo("tests") == 0)
        {
            RunTests.run();
        }
        else
        {
            readParams("config");

            Scanner sc = new Scanner(System.in);
            int in = 0;

            do
            {
                System.out.println("Select an action:");
                System.out.println("1) Add request");
                System.out.println("2) Watch requests");
                System.out.println("3) Pay for request");
                System.out.println("4) Confirm request");

                System.out.println("5) Good request");
                System.out.println("6) Bad request (not payed)");
                System.out.println("7) Bad request (not confirmed)");
                System.out.println("0) Exit");

                if (sc.hasNextInt())
                {
                    in = sc.nextInt();
                }
                else
                {
                    System.out.println("You must enter a number"); 
                    sc.nextLine();
                    in = -1;
                }

                switch(in)
                {
                    case 1:
                        {
                            quantity = readNewRequestParams(server, sysa, payingSystem, userName, quantity);
                            sendNewRequest(server.toString(), sysa.toString(), payingSystem.toString(), userName.toString(), quantity);
                            break;
                        }
                    case 2:
                        {
                            readWatchRequestParams(server, sysa, userName, DBHost, DBUser, DBPass);
                            sendWatchRequest(server.toString(), sysa.toString(), userName.toString(), DBHost, DBUser, DBPass);
                            break;
                        }
                    case 3:
                        {
                            int ID = 0;

                            ID = readPayingRequestParams(server, payingSystem, userName, ID);
                            sendPayingRequest(server.toString(), payingSystem.toString(), userName.toString(), ID);
                            break;
                        }
                    case 4:
                        {
                            int ID = 0;

                            ID = readUserAckParams(server, sysa, userName, ID);
                            sendUserAck(server.toString(), sysa.toString(), userName.toString(), ID);
                            break;
                        }
                    case 5:
                        {
                            sc = new Scanner(System.in);
                            read(sc, "quantity", quantity);
                            makeGoodRequest();
                            break;
                        }
                    case 6:
                        {
                            sc = new Scanner(System.in);
                            read(sc, "quantity", quantity);
                            makeBadRequest_1();
                            break;
                        }
                    case 7:
                        {
                            sc = new Scanner(System.in);
                            read(sc, "quantity", quantity);
                            makeBadRequest_2();
                            break;
                        }
                }
               
            }
            while (in != 0);
        }
    }

    /**
     *  Чтение строки со стандартного ввода. Если введена пустая строка, то берется значение по-умолчанию. 
     */
    private static void read(Scanner sc, String Name, StringBuffer value)
    {
        System.out.println(Name + " [ " + value + " ] : "); 
        String tempValue = sc.nextLine();
        if (tempValue.compareTo("") != 0)
        {
            value.delete(0, value.length());
            value.append(tempValue);
        }
    }

    /**
     *  Чтение числа со стандартного ввода. Если введнена пустая строка, то берется значение по-умолчанию.
     */
    private static int read(Scanner sc, String Name, Integer value)
    {
        System.out.println(Name + " [ " + value + " ] : "); 
        String tempValue = sc.nextLine();
        if (tempValue.compareTo("") != 0)
            value = Integer.parseInt(tempValue);
        return value;
    }

    /**
     * Чтение со стандартного ввода параметров для создания нового запроса на товар у системы заказчика.
     */
    public static int readNewRequestParams(StringBuffer server, StringBuffer sysa, StringBuffer payingSystem, StringBuffer userName, int quantity)
    {
        Scanner sc = new Scanner(System.in);
        read(sc, "Server", server);
        read(sc, "System A", sysa);
        read(sc, "Paying system", payingSystem);
        read(sc, "User name", userName);
        quantity = read(sc, "Quantity", quantity);
        return quantity;
    }

    /**
     *  Отправка сообщения с запросом о новом товаре системе заказчика.
     */
    public static void sendNewRequest(String server, String sysa, String payingSystem, String userName, int quantity)
    {
        try
        {
            JSONMessage mes = new JSONMessage(userName + "@" + server, sysa.toString(), "New request from user");
            mes.put("Type", "newRequest");
            mes.put("Quantity", quantity);
            mes.put("PayingSystem", payingSystem);
            mes.put("UserName", userName);
            new MessageSenderSMTP(server, portSMTP).send(mes);
            System.out.println("Message about new request to " + sysa + "have been send");
        }
        catch(Exception e)
        {
            System.out.println("Error when creating JSON message or sending it");
        }
    }
    
    /**
     * Чтение со стандартного ввода параметров для создания нового запроса на оплату товара.
     */
    public static int readPayingRequestParams(StringBuffer server, StringBuffer payingSystem, StringBuffer userName, int ID)
    {
        Scanner sc = new Scanner(System.in);
        read(sc, "Server", server);
        read(sc, "Paying system", payingSystem);
        read(sc, "User name", userName);
        ID = read(sc, "ID", ID);
        return ID;
    }

    /**
     *  Отправка сообщения с запросом о новом товаре системе заказчика.
     */
    public static void sendPayingRequest(String server, String payingSystem, String userName, int ID)
    {
        try
        {
            JSONMessage mes = new JSONMessage(userName + "@" + server, payingSystem.toString(), "New request from user");
            mes.put("Type", "newRequest");
            mes.put("ID", ID);
            new MessageSenderSMTP(server, portSMTP).send(mes);
            System.out.println("Message about paying for ID #" + ID + " to " + payingSystem.toString() + "have been send");
        }
        catch(Exception e)
        {
            System.out.println("Error when creating JSON message or sending it");
        }
    }

    /**
     *  Чтение со стандартного ввода параметров для создания подтверждения пользователя
     */
    private static int readUserAckParams(StringBuffer server, StringBuffer sysa, StringBuffer userName, int ID)
    {
        Scanner sc = new Scanner(System.in);
        read(sc, "Server", server);
        read(sc, "System A", sysa);
        read(sc, "User", userName);
        ID = read(sc, "ID", ID);
        return ID;
    }

    /**
     *  Отправка сообщения с подтверждением пользователя
     */
    public static void sendUserAck(String server, String sysa, String userName, int ID)
    {
        try
        {
            JSONMessage mes = new JSONMessage(userName + "@" + server, sysa, "Acknowledge from user");
            mes.put("Type", "ackUser");
            mes.put("ackOn", ID);
            new MessageSenderSMTP(server, portSMTP).send(mes);
            System.out.println("Confirmation from user about ID #" + ID + " to " + sysa + "have been send");
        }
        catch(Exception e)
        {
            System.out.println("Error when creating JSON message or sending it");
        }
    }

    /**
     *  Чтение параметров запроса на просмотр заявок
     */
    private static void readWatchRequestParams(StringBuffer server, StringBuffer sysa, StringBuffer userName, StringBuffer DBHost, StringBuffer DBUser, StringBuffer DBPass)
    {
        Scanner sc = new Scanner(System.in);
        read(sc, "Server", server);
        read(sc, "System A", sysa);
        read(sc, "User", userName);
        read(sc, "Database host", DBHost);
        read(sc, "Database user", DBUser);
        read(sc, "Database password", DBPass);
    }

    /**
     *  Выполнение запроса на просмотр заявок
     */
    public static void sendWatchRequest(String server, String sysa, String userName,StringBuffer DBHost, StringBuffer DBUser, StringBuffer DBPass)
    {
        db = new DBWrapper(DBHost.toString(), "systema", DBUser.toString(), DBPass.toString());
        db.connect();

        try
        {
            System.out.println("All requests, what are not done");
            ResultSet rs = db.select("Request", "User_Name = '" + userName + "' AND Payed*AckByUser*AckBySeller = 0");
            while (rs.next())
            {
                System.out.println(rs.getInt("ID"));
            }
        }
        catch(Exception e)
        {
            System.out.println("Error when selecting data from the database : " + e.getMessage());
        }
    }

    /**
     *  Создание серии запросов, которые приведут заявку в состояние завершения
     */
    public static void makeGoodRequest()
    {
        ResultSet rs = null;
        int ID = 0;

        db = new DBWrapper(DBHost.toString(), "systema", DBUser.toString(), DBPass.toString());
        db.connect();
        try
        {
            Statement statement = db.getConnection().createStatement();
            String query =  "SELECT MAX(ID) as ID FROM Request";
            rs = statement.executeQuery(query);
            rs.next();
            ID = rs.getInt("ID") + 1;
        }
        catch(Exception e)
        {
            System.out.println("Error when selecting data from the database : " + e.getMessage());
        }
 
        sendNewRequest(server.toString(), sysa.toString(), payingSystem.toString(), userName.toString(), quantity);

        sendPayingRequest(server.toString(), payingSystem.toString(), userName.toString(), ID);

        try
        {
            int n = 0;
            rs = db.select("Request", "ID = " + ID + " AND User_Name = '" + userName + "' AND Payed = 1");
            while(rs.next() == false && n < 60)
            {
                n++;
                Thread.sleep(3000);
                rs = db.select("Request", "ID = " + ID + " AND User_Name = '" + userName + "' AND Payed = 1");
            }
        }
        catch(Exception e)
        {
            System.out.println("Error when selecting data from the database : " + e.getMessage());

        }

        sendUserAck(server.toString(), sysa.toString(), userName.toString(), ID);
    }

    /**
     *  Создание сериии запросов, которые приведут заявку в состояние Cancel.
     *  Пользователь не заплатил.
     */
    public static void makeBadRequest_1()
    {
        ResultSet rs = null;
        int ID = 0;

        db = new DBWrapper(DBHost.toString(), "systema", DBUser.toString(), DBPass.toString());
        db.connect();
        try
        {
            Statement statement = db.getConnection().createStatement();
            String query =  "SELECT MAX(ID) as ID FROM Request";
            rs = statement.executeQuery(query);
            rs.next();
            ID = rs.getInt("ID") + 1;
        }
        catch(Exception e)
        {
            System.out.println("Error when selecting data from the database : " + e.getMessage());
        }
 
        sendNewRequest(server.toString(), sysa.toString(), payingSystem.toString(), userName.toString(), quantity);
    }

    /**
     *  Создание сериии запросов, которые приведут заявку в состояние Cancel.
     *  Пользователь не подтвердил заявку.
     */
    public static void makeBadRequest_2()
    {
        ResultSet rs = null;
        int ID = 0;

        db = new DBWrapper(DBHost.toString(), "systema", DBUser.toString(), DBPass.toString());
        db.connect();
        try
        {
            Statement statement = db.getConnection().createStatement();
            String query =  "SELECT MAX(ID) as ID FROM Request";
            rs = statement.executeQuery(query);
            rs.next();
            ID = rs.getInt("ID") + 1;
        }
        catch(Exception e)
        {
            System.out.println("Error when selecting data from the database : " + e.getMessage());
        }
 
        sendNewRequest(server.toString(), sysa.toString(), payingSystem.toString(), userName.toString(), quantity);

        sendPayingRequest(server.toString(), payingSystem.toString(), userName.toString(), ID);
    }
    private static DBWrapper db;
    private static StringBuffer sysa;
    private static StringBuffer server;
    private static StringBuffer payingSystem, userName;
    private static StringBuffer DBHost, DBUser, DBPass;
    private static int quantity;
    private static String portSMTP;

}
